function isalnum(c) {
    var zg =  /^[0-9a-zA-Z_]*$/;  
    if (!zg.test(c))  {  
        return false;  
    } else {  
        return true;  
    }
}

function tsvalidate(ts) {
    if (typeof ts !== 'string') {
        return false;
    }
    ts = ts.replace(/\s+/g, '');
    t1 = v_atom(ts);
    if (t1[0]) {
        return t1[1].length === 0;
    }
    return false;
}

function v_atom(ts) {
    console.log('v_atom', ts);
    r1 = v_void(ts);
    if (r1[0]) {
        return r1;
    }
    r2 = v_bool(ts);
    if (r2[0]) {
        return r2;
    }
    r3 = v_int(ts);
    if (r3[0]) {
        return r3;
    }
    r4 = v_float(ts);
    if (r4[0]) {
        return r4;
    }
    r5 = v_str(ts);
    if (r5[0]) {
        return r5;
    }
    r6 = v_json(ts);
    if (r6[0]) {
        return r6;
    }
    r7 = v_list(ts);
    if (r7[0]) {
        return r7;
    }
    r7 = v_list_loose(ts);
    if (r7[0]) {
        return r7;
    }
    r8 = v_map(ts);
    if (r8[0]) {
        return r8;
    }
    r8 = v_map_loose(ts);
    if (r8[0]) {
        return r8;
    }
    r9 = v_tuple(ts);
    if (r9[0]) {
        return r9;
    }
    r9 = v_tuple_loose(ts);
    if (r9[0]) {
        return r9;
    }
    r10 = v_option(ts);
    if (r10[0]) {
        return r10;
    }
    r10 = v_option_loose(ts);
    if (r10[0]) {
        return r10;
    }
    r11 = v_defined(ts);
    if (r11[0]) {
        return r11;
    }
    return [false, ts];
}

function v_void(ts) {
    console.log('v_void', ts);
    if (ts.startsWith('Void') || ts.startsWith('void')) {
        if (isalnum(ts[4])) {
            return [false, ts];
        }
        return [true, ts.slice(4)];
    }
    return [false, ts];
}

function v_bool(ts) {
    console.log('v_bool', ts);
    if (ts.startsWith('Bool') || ts.startsWith('bool')) {
        if (isalnum(ts[4])) {
            return [false, ts];
        }
        return [true, ts.slice(4)];
    }
    return [false, ts];
}

function v_int(ts) {
    console.log('v_int', ts);
    if (ts.startsWith('Int') || ts.startsWith('int')) {
        if (isalnum(ts[3])) { 
            return [false, ts];
        }
        return [true, ts.slice(3)];
    }
    return [false, ts];
}

function v_float(ts) {
    console.log('v_float', ts);
    if (ts.startsWith('Float') || ts.startsWith('float')) {
        if (isalnum(ts[5])) {
            return [false, ts];
        }
        return [true, ts.slice(5)];
    }
    return [false, ts];
}

function v_str(ts) {
    console.log('v_str', ts);
    if (ts.startsWith('Str') || ts.startsWith('str')) {
        if (isalnum(ts[3])) {
            return [false, ts];
        }
        return [true, ts.slice(3)];
    }
    return [false, ts];
}

function v_json(ts) {
    console.log('v_json', ts);
    if (ts.startsWith('Json') || ts.startsWith('json')) {
        if (isalnum(ts[4])) {
            return [false, ts];
        }
        return [true, ts.slice(4)];
    }
    return [false, ts];
}

function v_list(ts) {
    console.log('v_list', ts);
    if (ts.startsWith('List<') || ts.startsWith('list<')) {
        t1 = v_atom(ts.slice(5));
        if (t1[0]) {
            if (t1[1].startsWith('>')) {
                return [true, t1[1].slice(1)];
            }
        }
        return [false, ts];
    }
    return [false, ts];
}

function v_list_loose(ts) {
    console.log('v_list_loose', ts);
    if (ts.startsWith('[')) {
        t1 = v_atom(ts.slice(1));
        if (t1[0]) {
            if (t1[1].startsWith(']')) {
                return [true, t1[1].slice(1)];
            }
        }
    }
    return [false, ts];
}

function v_map(ts) {
    console.log('v_map', ts);
    if (ts.startsWith('Map<') || ts.startsWith('map<')) {
        t1 = v_atom(ts.slice(4));
        if (t1[0]) {
            if (t1[1].startsWith(',')) {
                t2 = v_atom(t1[1].slice(1));
                if (t2[0]) {
                    if (t2[1].startsWith('>')) {
                        return [true, t2[1].slice(1)];
                    }
                }
            }
        }
    }
    return [false, ts];
}

function v_map_loose(ts) {
    console.log('v_map_loose', ts);
    if (ts.startsWith('{')) {
        t1 = v_atom(ts.slice(1));
        if (t1[0]) {
            if (t1[1].startsWith(',')) {
                t2 = v_atom(t1[1].slice(1));
                if (t2[0]) {
                    if (t2[1].startsWith('}')) {
                        return [true, t2[1].slice(1)];
                    }
                }
            }
        }
    }
    return [false, ts];
}

function v_tuple(ts) {
    console.log('v_tuple', ts);
    if (ts.startsWith('(')) {
        ts = ts.slice(1);
        var count = 0;
        while (true) {
            t1 = v_atom(ts);
            if (t1[0]) {
                count++;
                if (t1[1].startsWith(')')) {
                    if (count >= 2) {
                        return [true, t1[1].slice(1)];
                    } else {
                        return [false, ts];
                    }
                } else if (t1[1].startsWith(',')) {
                    ts = t1[1].slice(1);
                } else {
                    return [false, ts];
                }
            } else {
                return [false, ts];
            }
        }
    }
    return [false, ts];
}

function v_tuple_loose(ts) {
    console.log('v_tuple_loose', ts);
    if (ts.startsWith('tuple<') || ts.startsWith('Tuple<')) {
        ts = ts.slice(6);
        var count = 0;
        while (true) {
            t1 = v_atom(ts);
            if (t1[0]) {
                count++;
                if (t1[1].startsWith('>')) {
                    if (count >= 2) {
                        return [true, t1[1].slice(1)];
                    } else {
                        return [false, ts];
                    }
                } else if (t1[1].startsWith(',')) {
                    ts = t1[1].slice(1);
                } else {
                    return [false, ts];
                }
            } else {
                return [false, ts];
            }
        }
    }
    return [false, ts];
}

function v_option(ts) {
    console.log('v_option', ts);
    if (ts.startsWith('?')) {
        t1 = v_atom(ts.slice(1));
        if (t1[0]) {
            return [true, t1[1]];
        }
    }
    return [false, ts];
}

function v_option_loose(ts) {
    console.log('v_option_loose', ts);
    if (ts.startsWith('Option<') || ts.startsWith('option<')) {
        t1 = v_atom(ts.slice(7));
        if (t1[0]) {
            if (t1[1].startsWith('>')) {
                return [true, t1[1].slice(1)];
            }
        }
        return [false, ts];
    }
    return [false, ts];
}

function v_defined(ts) {
    console.log('v_defined', ts);
    let ts0 = ts;
    let name = ''
    while (ts.length > 0 && isalnum(ts[0])) {
        name += ts[0];
        ts = ts.slice(1);
    }
    if (name === 'List' || name === 'Map' || name === 'Tuple' || name === 'Option' || name === 'list' || name === 'map' || name === 'tuple' || name === 'option') {
        return [false, ts0];
    }
    var pat = /^[a-zA-Z_][a-zA-Z0-9_]*$/;
    if (pat.test(name)) {
        return [true, ts];
    }
    return [false, ts0];
}
